package com.example.service;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.request.*;
import com.alipay.api.response.*;
import com.example.consts.OrderStatus;
import com.example.consts.TradeStatus;
import com.example.pojo.entity.Orders;
import com.google.gson.Gson;
import com.google.gson.internal.LinkedTreeMap;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;

@Slf4j
@Service
public class AlipayServiceImpl implements AlipayService {
    @Autowired
    private OrderInfoService orderInfoService;

    @Autowired
    private AlipayClient alipayClient;
    @Autowired
    private Environment config;

    private final ReentrantLock lock = new ReentrantLock();

    @Override
    public String tradeCreate(Integer resuId,Integer jsId) {
        try {

//        生成订单
            Orders orders = orderInfoService.createOrderByResuId(resuId,jsId);
            if (orders == null){
                return null;
            }

            //        调用支付宝接口
            AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
            //异步接收地址，仅支持http/https，公网可访问
            request.setNotifyUrl(config.getProperty("alipay.notify-url"));
//            System.out.println("============================");
//            System.out.println(request.getNotifyUrl());
            //同步跳转地址，仅支持http/https
            request.setReturnUrl(config.getProperty("alipay.return-url"));
            /******必传参数******/
            JSONObject bizContent = new JSONObject();
            //商户订单号，商家自定义，保持唯一性
            bizContent.put("out_trade_no", orders.getOrdNumber());
            //支付金额，最小值0.01元
            BigDecimal total = new BigDecimal(orders.getOrdTotalFee().toString());
            bizContent.put("total_amount", total);
            //订单标题，不可使用特殊符号
            bizContent.put("subject", orders.getOrdTitle());
            //电脑网站支付场景固定传值FAST_INSTANT_TRADE_PAY
            bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");

            request.setBizContent(bizContent.toString());

            //        执行请求,调用支付宝接口
            AlipayTradePagePayResponse response = alipayClient.pageExecute(request);
            if (response.isSuccess()) {
                System.out.println("调用成功");
            } else {
                System.out.println("调用失败");
                throw new RuntimeException("创建支付交易失败");
            }
            return response.getBody();
        } catch (AlipayApiException e) {
            e.printStackTrace();
            throw new RuntimeException("创建支付交易失败");
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void processOrder(Map<String, String> params) {
        log.info("处理订单业务");
        //获取订单号
        String ordNum1 = params.get("out_trade_no");
        Long ordNum = Long.parseLong(ordNum1);

        System.out.println("=订单处理业务=");
//        防止高并发-多台支付宝服务器同时发送通知-可重用锁
        if (lock.tryLock()){
                try {
    //        处理重复通知,防止表单重复提交-接口幂等性
                    String orderStatus = orderInfoService.getOrderStatus(ordNum);
                    if (!OrderStatus.NOTPAY.getType().equals(orderStatus)) {
                        System.out.println("=我也不知道=");
                        return;
                    }

    //        更新订单状态
                    System.out.println("==============================================");
                    orderInfoService.updateStatusByOrdNum(ordNum, OrderStatus.SUCCESS.getType());
                }finally {
//                    需要主动释放
                    lock.unlock();
                }
            }
    }

    @Override
    public void cancelOrder(String ordNum) {
//        调用支付宝的统一收单交易关闭按钮
        this.closeOrder(ordNum);

//        更新订单状态
        Long ordNum1 = Long.parseLong(ordNum);
        orderInfoService.updateStatusByOrdNum(ordNum1,OrderStatus.CANCEL.getType());
    }

    //    关单接口调用
    private void closeOrder(String ordNum) {
        log.info("关单接口调用,订单号----->"+ordNum);
        try {
            AlipayTradeCloseRequest request = new AlipayTradeCloseRequest();
            JSONObject bizContent = new JSONObject();
            bizContent.put("out_trade_no", ordNum);
            request.setBizContent(bizContent.toString());
            AlipayTradeCloseResponse response = alipayClient.execute(request);
            if(response.isSuccess()){
                System.out.println("关单接口调用成功");
            } else {
                System.out.println("关单接口调用失败");
//                throw new RuntimeException("关单接口调用失败");
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
            throw new RuntimeException("关单接口调用失败");
        }
    }

//    调用支付宝支付查单接口主动发起支付查单-返回一个json字符串
    @Override
    public String queryOrder(String ordNum) {
        log.info("查单接口调用");
        try {
            AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
            JSONObject bizContent = new JSONObject();
            bizContent.put("out_trade_no", ordNum);
            request.setBizContent(bizContent.toString());
            AlipayTradeQueryResponse response = alipayClient.execute(request);
            if (response.isSuccess()) {
                System.out.println("调用成功");
                return response.getBody();
            } else {
                //订单不存在,支付宝端尚未创建订单
                System.out.println("调用失败");
                return null;
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
            throw new RuntimeException("查单接口调用失败");
        }
    }

//    查单并修改订单状态-未创建:更新客户端状态;已支付:更新客户端状态;未支付:调用关单接口关闭订单,并更新客户端状态
    @Override
    public void checkOrdStatus(Long ordNum) {
        log.warn("根据订单号核实订单状态--->"+ordNum);

        String ordNum1 = ordNum.toString();
        String result = this.queryOrder(ordNum1);

//        订单未创建
        if(result == null){
            log.warn("核实订单未创建--->"+ordNum);
            orderInfoService.updateStatusByOrdNum(ordNum,OrderStatus.CLOSED.getType());
        }

//      订单未支付
//      解析查单响应的结果
        Gson gson = new Gson();
        HashMap<String, LinkedTreeMap> resultMap = gson.fromJson(result, HashMap.class);
//        嵌套Json,会把子节点转换成treeMap
        LinkedTreeMap tradeQueryResponse = resultMap.get("alipay_trade_query_response");
        String tradestatus = (String) tradeQueryResponse.get("trade_status");
        if (TradeStatus.NOTPAY.getType().equals(tradestatus)){
            log.warn("核实订单未支付--->"+ordNum);

//            调用关单接口关闭订单,并更新客户端状态
                    this.closeOrder(ordNum1);
                    orderInfoService.updateStatusByOrdNum(ordNum,OrderStatus.CLOSED.getType());
        }

//        订单已支付,异步通知未接收,主动查单更新状态
        if (TradeStatus.SUCCESS.getType().equals(tradestatus)){
            log.warn("核实订单已支付--->"+ordNum);

//         更新客户端状态
           orderInfoService.updateStatusByOrdNum(ordNum,OrderStatus.SUCCESS.getType());
        }
    }

//    订单退款
    @Override
    public void refund(String ordNum) {
        log.info("处理退款业务");
        try {
//        调用统一收单交易退款接口
            AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
            JSONObject bizContent = new JSONObject();
            Long ordNum1 = Long.parseLong(ordNum);
            Orders orders = orderInfoService.getOrdbyOrdNum(ordNum1);
            Double ordTotalFee = orders.getOrdTotalFee();
            bizContent.put("out_trade_no",ordNum);
            bizContent.put("refund_amount",ordTotalFee);

            request.setBizContent(bizContent.toString());
            AlipayTradeRefundResponse response = alipayClient.execute(request);

//            支付宝会同步返回退款结果
            if (response.isSuccess()) {
                System.out.println("调用成功");
                orderInfoService.updateStatusByOrdNum(ordNum1,OrderStatus.REFUND_SUCCESS.getType());
//                orders.setIfRefund("Yes");
            } else {
                orderInfoService.updateStatusByOrdNum(ordNum1,OrderStatus.REFUND_ABNORMAL.getType());
            }
        }catch (AlipayApiException e) {
            e.printStackTrace();
            throw new RuntimeException("查单接口调用失败");
        }
    }

//    调用支付宝退款查单接口主动发起退款查单
    @Override
    public String queryRefund(String ordNum) {
        log.info("主动查询退款");
        try {
            AlipayTradeFastpayRefundQueryRequest request = new AlipayTradeFastpayRefundQueryRequest();
            JSONObject bizContent = new JSONObject();
            bizContent.put("out_trade_no", ordNum);
            bizContent.put("out_request_no", ordNum);
            request.setBizContent(bizContent.toString());
            AlipayTradeFastpayRefundQueryResponse response = alipayClient.execute(request);
            if (response.isSuccess()) {
                System.out.println("调用成功");
                return response.getBody();
            } else {
                System.out.println("调用失败");
                return null;
            }
        }catch (AlipayApiException e) {
            e.printStackTrace();
            throw new RuntimeException("查单接口调用失败");
        }
    }
}
